package studio.xiaoyun.web.resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import studio.xiaoyun.core.exception.XyException;
import studio.xiaoyun.core.parameter.Parameter;

import java.lang.reflect.Method;
import java.util.*;

/**
 * 辅助类，用于将实体类转换为资源类。
 * @author 岳正灵
 */
@Service
public class ResourceUtil {
    private Logger logger = LoggerFactory.getLogger(ResourceUtil.class);

    /**
     * 将实体类转换为资源类。
     * <p>如果实体类中的属性名和资源类中的相同，实体类中属性的值将被复制到资源类中</p>
     * @param entitys   实体类
     * @param parameter 搜索参数
     * @param clazz     资源类
     * @param <T>       资源类的类型
     * @return 资源类
     */
    public <T extends Resource> List<T> toResource(List<?> entitys, Parameter parameter, Class<T> clazz) {
        if (entitys.isEmpty()) {
            return Collections.emptyList();
        }
        Map<String, Method> getMethodMap = new HashMap<>();
        Map<String, Method> setMethodMap = new HashMap<>();
        //获得所有get开头的所有方法
        for (Method m : entitys.get(0).getClass().getMethods()) {
            if (m.getName().startsWith("get") && m.getParameterCount() == 0) {
                getMethodMap.put(m.getName().substring(3), m);
            }
        }
        //获得所有set开头的方法
        for (Method m : clazz.getMethods()) {
            if (m.getName().startsWith("set") && m.getParameterCount() == 1) {
                setMethodMap.put(m.getName().substring(3), m);
            }
        }
        List<T> resources = new ArrayList<>();
        for (Object entity : entitys) {
            try {
                T resource = clazz.newInstance();
                for (Map.Entry<String,Method> entry: setMethodMap.entrySet()) {
                    Method getMethod = getMethodMap.get(entry.getKey());
                    if (getMethod != null){
                        Object value = getMethod.invoke(entity);
                        entry.getValue().invoke(resource, value);
                    }
                }
                resources.add(resource);
            } catch (Exception e) {
                logger.error("实体类转换为资源类失败", e);
                throw new XyException("实体类转换为资源类失败",e);
            }
        }
        setNull(resources, parameter);  //将多余的属性设置为null
        return resources;
    }

    void setNull(List<?> resources, Parameter parameter) {
        if (parameter == null || parameter.getIncludeField().isEmpty()) return;
        List<String> fields = parameter.getIncludeField();
        List<Method> methodList = new ArrayList<>();
        for (Method method : resources.get(0).getClass().getMethods()) {
            if (method.getName().startsWith("set") && method.getParameterCount() == 1 && method.getReturnType() == Void.TYPE) {
                String name = method.getName().substring(3);
                if (!fields.stream().anyMatch(item -> item.equalsIgnoreCase(name))) {
                    methodList.add(method);
                }
            }
        }
        for (Method method : methodList) {
            for (Object resource : resources) {
                try {
                    method.invoke(resource, (Object) null);
                } catch (Exception e) {
                    logger.warn("执行方法" + method.getName() + "时出错", e);
                }
            }
        }
    }

}
